package com.zeyu.framework.tools.report.convert.pool;

import com.google.common.collect.Maps;
import com.zeyu.framework.core.common.mapper.JsonMapper;
import com.zeyu.framework.tools.report.convert.server.Server;
import com.zeyu.framework.tools.report.convert.server.ServerState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

/**
 * server 对象工厂类
 * Created by zeyuphoenix on 16/9/3.
 */
public class ServerObjectFactory implements ObjectFactory<Server> {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(ServerObjectFactory.class);

    // ================================================================
    // Fields
    // ================================================================

    // server 信息
    public String exec;
    public String script;
    private String host;
    private int basePort;
    // 超时时间
    private int readTimeout;
    private int connectTimeout;
    private int maxTimeout;
    // 使用端口列表
    private static Map<Integer, PortStatus> portUsage = Maps.newHashMap();

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    @Override
    public Server create() {
        logger.debug("in makeObject, " + exec + ", " + script + ", " + host);
        Integer port = this.getAvailablePort();
        portUsage.put(port, PortStatus.BUSY);
        return new Server(exec, script, host, port, connectTimeout,
                readTimeout, maxTimeout);
    }

    @Override
    public boolean validate(Server server) {
        boolean isValid = false;
        try {
            if (server.getState() != ServerState.IDLE) {
                logger.debug("server didn\'t pass validation");
                return false;
            }
            // String result = server.request("{\"status\":\"isok\"}");
            // String result = server.request("status=isok");
            Map<String, Object> params = Maps.newHashMap();
            params.put("status", "isok");
            String result = server
                    .request("body='" + JsonMapper.toJsonString(params) + "'");
            if (result.contains("OK")) {
                isValid = true;
                logger.debug("server passed validation");
            } else {
                logger.debug("server didn\'t pass validation");
            }
        } catch (Exception e) {
            logger.error("Error while validating object in Pool: "
                    + e.getMessage());
        }
        return isValid;
    }

    @Override
    public void destroy(Server server) {
        ServerObjectFactory.releasePort(server.getPort());
        server.cleanup();
    }

    @Override
    public void activate(Server server) {
        server.setState(ServerState.ACTIVE);
    }

    @Override
    public void passivate(Server server) {
        server.setState(ServerState.IDLE);
    }

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    public static void releasePort(Integer port) {
        logger.debug("Releasing port " + port);
        portUsage.put(port, PortStatus.FREE);
    }

    public Integer getAvailablePort() {
        for (Map.Entry<Integer, PortStatus> entry : portUsage.entrySet()) {
            if (PortStatus.FREE == entry.getValue()) {
                // return available port
                logger.debug("Port usage " + portUsage.toString());
                return entry.getKey();
            }
        }
        // if no port is free
        logger.debug("Nothing free in Port usage " + portUsage.toString());
        return basePort + portUsage.size();
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    public String getExec() {
        return exec;
    }

    public void setExec(String exec) {
        this.exec = exec;
    }

    public String getScript() {
        return script;
    }

    public void setScript(String script) {
        this.script = script;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getBasePort() {
        return basePort;
    }

    public void setBasePort(int basePort) {
        this.basePort = basePort;
    }

    public int getReadTimeout() {
        return readTimeout;
    }

    public void setReadTimeout(int readTimeout) {
        this.readTimeout = readTimeout;
    }

    public int getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public int getMaxTimeout() {
        return maxTimeout;
    }

    public void setMaxTimeout(int maxTimeout) {
        this.maxTimeout = maxTimeout;
    }

    // ================================================================
    // Private Methods
    // ================================================================

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    /**
     * 对象接口状态
     */
    private enum PortStatus {
        BUSY, FREE
    }

    // ================================================================
    // Test Methods
    // ================================================================

}
